#include <iostream>
#include <stdio.h>
#include <strings.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include<sys/types.h>
#include<sys/wait.h>


#include "Log.hpp"
#include "Protocol.hpp"

volatile bool quitSer = false;

static Response calculator(Request &req)
{
    Response res;
    switch (req.getOp())
    {
    case '+':
        res.result_ = req.getX() + req.getY();
        break;
    case '-':
        res.result_ = req.getX() - req.getY();
        break;
    case '/':
        {
            if(req.getY() == 0)
            {
                res.exitCode_ = -1;  // -1，除0
            }
            else
            {
                res.result_ = req.getX() / req.getY();
            }
        }
        break;
    case '*':
        res.result_ = req.getX() * req.getY();
        break;
    case '%':
        {
            if(req.getY() == 0) res.exitCode_ = -2; // -2，模0
            else res.result_ = req.getX() % req.getY();
        }
        break;
    default:
        res.exitCode_ = -3;  //     
        break;
    }

    std::cout << "result" << res.result_ << std::endl;
    return res;
}

void netcal(int sockfd, std::string &clientIp, uint16_t clientPort)
{
    assert(sockfd > 0);
    assert(!clientIp.empty());
    assert(clientPort >= 1024);

    std::string inbuffer;
    while (true)
    {
        Request req;
        char buf[128];
        ssize_t s = read(sockfd, buf, sizeof(buf) - 1);
        if (s == 0)
        {
            logMessage(NOTICE, "client[%s : %d] close sockfd, server done...", clientIp.c_str(), clientPort);
            break;
        }
        else if (s < 0)
        {
            logMessage(WARINING, "read client[%s:%d] error, errorcode: %d, errormessage: %s",
                       clientIp.c_str(), clientPort, errno, strerror(errno));
            break;
        }

        // read success
        buf[s] = 0;
        inbuffer += buf;
        std::cout << "inbuffer: " << inbuffer << std::endl;

        // 1. 检查inbuffer是不是已经有了一个strPackage
        uint32_t packageLen;
        std::string package = decode(inbuffer, &packageLen);
        if (packageLen == 0)
            continue; // 无法提取一个完整报文
        std::cout << package << std::endl;

        // 2. 已经获得一个完整package
        if (req.deserialization(package))
        {
            req.debug();
            // 3. 处理逻辑, 输入的是一个req，得到一个resp
            Response res = calculator(req);
            // 4. 对res进行序列化
            std::string resPackage;
            res.serialization(&resPackage);
            // 5. 对报文进行encode --
            resPackage = encode(resPackage, resPackage.size());
            // 6. 简单进行发送 -- 后续处理
            write(sockfd, resPackage.c_str(), resPackage.size());
        }
        else
        {
            logMessage(WARINING, "deserialization failed...");
        }
    }
}

void Usage(void *vgs)
{
    std::cout << "Usage:./tcpserver port ip" << std::endl;
}

class server
{
public:
    server(int port, std::string ip = "")
        : sockfd_(-1), ip_(ip), port_(port)
    {
    }
    ~server()
    {
    }

public:
    void init()
    {
        // 1. 创建套接字
        sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd_ < 0)
        {
            logMessage(FATAL, "socket:%s[%d]", strerror(errno), sockfd_);
            exit(SOCK_ERR);
        }
        logMessage(DEBUG, "socket success..");

        // 2.填充域
        struct sockaddr_in local;
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        ip_.empty() ? (local.sin_addr.s_addr = INADDR_ANY) : (inet_aton(ip_.c_str(), &local.sin_addr));

        // 3. 绑定网络信息
        if (bind(sockfd_, (const struct sockaddr *)&local, sizeof(local)) < 0)
        {
            logMessage(FATAL, "bind:%s[%d]", strerror(errno), sockfd_);
            exit(BIND_ERR);
        }
        logMessage(DEBUG, "bind success...");

        // 4. 监听套接字
        if (listen(sockfd_, 5) < 0)
        {
            logMessage(FATAL, "listen:%s[%d]", strerror(errno), sockfd_);
            exit(LISTEN_ERR);
        }
        logMessage(DEBUG, "listen success...");

        // 完成
    }

    void start()
    {
        char inbuffer_[1024]; // 用来接收客户端发来的消息
        // 提供服务
        while (true)
        {
            quitSer = false;

            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            // 5. 获取连接, accept 的返回值是一个新的socket fd
            int serviceSock = accept(sockfd_, (struct sockaddr *)&peer, &len);
            if (serviceSock < 0)
            {
                // 获取链接失败
                logMessage(WARINING, "accept: %s[%d]", strerror(errno), serviceSock);
                continue;
            }
            logMessage(DEBUG, "accept success");

            pid_t id = fork();
            if(id == 0)
            {
                pid_t tid = fork();
                if(tid == 0)
                {
                    uint16_t peerPort = htons(peer.sin_port);
                    std::string peerIp = inet_ntoa(peer.sin_addr);
                    netcal(serviceSock, peerIp, peerPort);
                }

                exit(0);
            }

            int ret = waitpid(id, nullptr, 0);
            if(ret < 0)
            {
                logMessage(WARINING, "wait child error:%d", errno);
            }
            logMessage(DEBUG, "wait success...");
        }
    }

private:
    int sockfd_;
    uint16_t port_;
    std::string ip_;
};

// ./tcpserver port ip
int main(int argc, char *argv[])
{
    if (argc < 2 || argc > 3)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }

    uint16_t port = atoi(argv[1]);
    std::string ip;
    if (argc == 3)
        ip = argv[2];

    server tcpSer(port, ip);
    tcpSer.init();
    tcpSer.start();
    return 0;
}
